package com.tianjin.design.flyweight;

/**
*
* @Description: 享元模式# 结构型模式
 * 1、解释：运用共享技术有效的支持大量细粒度的对象。
 *         面向对象技术可以解决一些灵活性或可扩展性问题,但需在系统中增加类和对象的个数.当对象数量太多时,将导致运行代价过高，
 *         带来性能下降等问题.享元模式正是为解决这一类问题而诞生的.
 *         享元模式(Flyweight Pattern)又称为轻量级模式,是对象池的一种实现.类似于线程池,线程池可以避免不停的创建和销毁多个对象，
 *         消耗性能.提供了减少对象数量从而改善应用所需的对象结构的方式。
 *         其宗旨是共享细粒度对象，将多个对同一对象的访问集中起来，不必为每个访问者创建一个单独的对象，从此来降低内存的消耗。
 *         享元模式把一个对象的状态分为内部状态和外部状态，内部状态即是不变的，外部状态是变化的,然后通过共享不变的部分,达到减少对象数量并节约内存的目的.
 *         享元模式的本质是缓存共享对象,降低内存消耗.
 *
 *         到这里不免想到单例模式：
 *              单例模式是类级别的，一个类只能有一个对象实例；
 *              享元模式是对象级别的，可以有多个对象实例，多个变量引用同一个对象实例；
                享元模式主要是为了节约内存空间，提高系统性能，而单例模式主要为了可以共享数据；
 *
 * 2、使用场景：主要是用来共享细粒度对象，降低创建相同对象时内存的消耗，我是这么理解的，多个相同类的对象可能有相同的行为，这时可以共享这些行为，
 *          例如人类，吃饭都得用工具，但是每个国家、每个人又可能是不同的，所以不同的部分可以通过外部状态去控制，对于相同部分通过内部状态控制。
 *          这里需要注意可以共享，但是并不是强制共享，这里就以吃饭为例，中国人用筷子，美国人用刀子，所以所有中国人可以共享一个吃饭工具，
 *          但是也可能会有不用筷子的（也就是不强制人共享，中国人就必须要用筷子吗？不一定）
 *          。
 * 3、代码实现思路：以2例子描述思路
 *      3-1 首先需要有一个支持吃饭使用工具享元抽象类 PeopleFlyWeight
 *      3-2 声明具体的共享类
 *          中国人 ChineseFlyWeight
 *          美国人 AmericanFlyWeight
 *      3-3 为了控制共享对象的使用，还需要一个共享对象工厂类 PeopleFlyWeightFactory，预制多类中国人和美国人
 *      3-4 使用如Test中main，对于不想共享的对象可以使用UnsharedPeopleFlyWeight
 *      3-5 此时考虑一个问题，每个人是不同的，现在代码中无法体现，所以需要使用外部状态来控制，这里使用一个实体类User来表示每一个人
 *          共享对象中接收外部状态参数以达到体现每一个人的目的
 *
*/
public class Test {

    public static void main(String[] args) {

        PeopleFlyWeightFactory factory = new PeopleFlyWeightFactory();
        PeopleFlyWeight peopleFlyWeight1 = factory.getPeopleFlyWeight("china-east");
        PeopleFlyWeight peopleFlyWeight2 = factory.getPeopleFlyWeight("china-east");
        PeopleFlyWeight peopleFlyWeight3 = factory.getPeopleFlyWeight("china-east");
        PeopleFlyWeight peopleFlyWeight4 = factory.getPeopleFlyWeight("china-east");

        User user1 = new User();
        user1.setName("user1");
        User user2 = new User();
        user2.setName("user2");
        User user3 = new User();
        user3.setName("user3");
        User user4 = new User();
        user4.setName("user4");

        peopleFlyWeight1.eatTool(user1);
        peopleFlyWeight2.eatTool(user2);
        peopleFlyWeight3.eatTool(user3);
        peopleFlyWeight4.eatTool(user4);

        System.out.println("此时peopleFlyWeight1-4都是同一个实例，只创建一次实例："+ peopleFlyWeight1.equals(peopleFlyWeight2));
        System.out.println("此时peopleFlyWeight1-4都是同一个实例，只创建一次实例："+ peopleFlyWeight2.equals(peopleFlyWeight3));
        System.out.println("此时peopleFlyWeight1-4都是同一个实例，只创建一次实例："+ peopleFlyWeight3.equals(peopleFlyWeight4));

        System.out.println("多个对象指向同一个实例，节省空间");
    }
}
